import React, { Component } from 'react';
import _ from 'underscore';
import moment from 'moment';
import cx from 'classnames';

/**
 * 获取一行日历的数据要补多少天。
 * @param {int} dayInWeek 待绘制的第一个日期是周几：前面的日期是需要补充的。
 * @param {int} firstColumnDay 第一天是周几：缺省值 0 表示周日，即从周日开始，1 表示周一，依此类推。
 * @return {int} 需要补充的天数：需要补一天就返回数字 1。
 */
function getAddDays(dayInWeek, firstColumnDay = 0) {
  dayInWeek = dayInWeek === 0 ? 7 : dayInWeek;
  firstColumnDay = firstColumnDay === 0 ? 7 : firstColumnDay;

  if (dayInWeek === firstColumnDay) {
    return 0;
  } else if (dayInWeek < firstColumnDay) {
    return 7 - (firstColumnDay - dayInWeek);
  } else {
    return dayInWeek - firstColumnDay;
  }
} // getAddDays

/**
 * 获取指定的月份有多少行数据。
 * @param {int} monthValue 时间刻度，比如 Date.now()。
 * @param {int} firstColumnDay 第一天是周几：缺省值 0 表示周日，即从周日开始，1 表示周一，依此类推。
 * @return {int} 指定月份默认情况下绘制的 Calendar 控件行数。
 */
export function calendarRowCount(monthValue, firstColumnDay = 0) {
  let currentValue = moment(monthValue)
      , dayInWeek = currentValue.startOf('months').day()  // 指定的月份从周几开始：周日返回 0，周一返回 1，依此类推。
      , date = currentValue.endOf('months').date();       // 指定的月份最后一天的日期：31 号返回 31，28 号返回 28。

  let add = getAddDays(dayInWeek, firstColumnDay);
  return Math.ceil((add + date) / 7.0);
} // calendarRowCount

/**
 * 日历周几的标题：第一天是周日，第二天是周一，第三天是周二，依次类推。
 */
export const dayTitles = ['日', '一', '二', '三', '四', '五', '六'];

export default class DatePickerCore extends Component {
  calendar(firstColumnDay = 0) {
    let currentValue = moment(this.props.monthValue).startOf('months')
      , rowCount = this.props.rowCount || calendarRowCount(this.props.monthValue, firstColumnDay) // 获取需要计算的日历行数。
      , subtractDayCount = getAddDays(currentValue.day(), firstColumnDay) // 获取需要减去的天数：从 firstColumnDay 指定的日期开始：0 表示那一周的周日，1 表示那一周的周一，依此类推。
      , currentDay = currentValue.subtract(subtractDayCount, 'days');     // 获取日历控件的第一天。

    let rows = [];
    for (let i = 0; i < rowCount; i++) {
      let row = [];
      for (let j = 0; j < 7; j++) {
        row.push(currentDay.valueOf());
        currentDay = currentDay.add(1, 'days');
      }
      rows.push(row);
    }
    return rows;
  } // calendar

  selectDayHandler(item) {
    if (this.props.onSelectingDay) {
      this.props.onSelectingDay(item);
    }
  } // selectDayHandler

  movingPreviousHandler() {
    if (this.props.onMovingPrevious) {
      let previousValue = moment(this.props.monthValue).startOf('month').subtract(1, 'months').valueOf();
      this.props.onMovingPrevious(previousValue);
    }
  } // movingPreviousHandler

  movingNextHandler() {
    if (this.props.onMovingNext) {
      let nextValue = moment(this.props.monthValue).startOf('month').subtract(1, 'months').valueOf();
      this.props.onMovingNext(nextValue);
    }
  } // movingPreviousHandler

  getColumnNames() {
    let columnNames = []
      , { firstColumnDay: day } = this.props;

      for (let index = 0; index < 7; index++) {
        columnNames.push(dayTitles[(index + day) % 7]);
      }

    return columnNames;
  } // getColumnNames

  render() {
    let firstDay = moment(this.props.monthValue).startOf('months')
        , year = firstDay.year()                                  // 指定的年份：2016 年获取的值为 2016。
        , month = firstDay.month()                                // 指定的月份：5 月份获取的值为 4。
        , lastDay = moment(this.props.monthValue).endOf('months') // 指定的月份最后一天的日期：31 号返回 31，28 号返回 28。
        , rows = this.calendar(this.props.firstColumnDay)         // 获取渲染的日历。
        , disabledCallback = this.props.disabledCallback
        , columnNames = this.getColumnNames();

    return (
      <div className="calendar-date" style={ this.props.style }>
        <table className="table-condensed">
          <thead>
            <tr>
              <th>
                {
                  this.props.canMovePrevious
                    ? (
                      <i className="iconfont arrow" onClick={ this.movingPreviousHandler.bind(this) }>
                        &#xe63e;
                      </i>
                    ) : null
                }
              </th>
              <th colSpan="5">
                { year } 年 { month + 1 } 月
              </th>
              <th>
                {
                  this.props.canMoveNext
                    ? (
                      <i className="iconfont arrow" onClick={ this.movingNextHandler.bind(this) }>
                        &#xe63f;
                      </i>
                    ) : null
                }
              </th>
            </tr>
            <tr>{ _.map(columnNames, (p, i) => <th key={ i }>{ p }</th>) }</tr>
          </thead>
          <tbody>
            {
              _.map(rows, row => (
                <tr key={ row[0] }>
                  {
                    _.map(row, item => {
                      let value = moment(item).startOf('day');
                      if (value.isBefore(firstDay) || value.isAfter(lastDay) || (disabledCallback ? disabledCallback(item) : false)) {
                        return (
                          <td className="disabled" key={ item }>
                            { value.date() }
                          </td>
                        );
                      } else {
                        return (
                          <td
                            key={ item }
                            onClick={ this.selectDayHandler.bind(this, item) }
                            className={ cx({
                              active: value.isSame(this.props.selectedMinDay ? moment(this.props.selectedMinDay).startOf('day') : null) ||
                                      value.isSame(this.props.selectedMaxDay ? moment(this.props.selectedMaxDay).startOf('day') : null),
                              left: value.isSame(this.props.selectedMinDay ? moment(this.props.selectedMinDay).startOf('day') : null),
                              right: value.isSame(this.props.selectedMaxDay ? moment(this.props.selectedMaxDay).startOf('day') : null),
                              transition: value.add(1, 'seconds')
                                               .isBetween(this.props.selectedMinDay ? moment(this.props.selectedMinDay).startOf('day') : null,
                                                          this.props.selectedMaxDay ? moment(this.props.selectedMaxDay).endOf('day') : null)
                            }) }>
                            { value.date() }
                          </td>
                        )
                      }
                    })
                  }
                </tr>
              ))
            }
          </tbody>
        </table>
      </div>
    );
  } // render
}

DatePickerCore.defaultProps = {
  rowCount: null, // 指定该月的日历需要渲染多少行，比如：5
  monthValue: moment().valueOf(), // 要渲染的月份，默认值是当前时间，表示渲染当月的日历
  selectedMinDay: null, // 表示已经选中的最小日期，比如：moment().valueOf()
  selectedMaxDay: null, // 表示已经选中的最大日期，比如：moment().valueOf()
  disabledCallback: null, // 表示一个不可用的回调函数，格式为 p => true：参数 p 表示回调的日期，返回 true 表示不可用
  onSelectingDay: null, // 表示在点击一个可选的日期，但时的回调：
  canMovePrevious: true,
  onMovingPrevious: null,
  canMoveNext: true,
  onMovingNext: null,
  firstColumnDay: 0,
  style: {}
}
